{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This notebook produces: \n",
    "* Figures 1, 2, and 3 from the Online Appendix, \n",
    "* Figure 4 from Further Supplement Information, and\n",
    "* Table 5 from Further Supplemental Information."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Import Libraries and Set Project Directory"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Data Analysis\n",
    "import pandas as pd\n",
    "import numpy as np\n",
    "from scipy import stats\n",
    "\n",
    "# Plotting\n",
    "import matplotlib.pyplot as plt \n",
    "import seaborn as sns; sns.set(color_codes=True)\n",
    "from textwrap3 import wrap\n",
    "plt.rcParams['font.sans-serif'] = 'Times New Roman'\n",
    "plt.rcParams['font.family'] = 'sans-serif'\n",
    "\n",
    "# Jupyter display settings\n",
    "pd.options.display.max_columns = None\n",
    "pd.options.display.max_rows = 100\n",
    "pd.options.display.float_format = '{:,.3f}'.format\n",
    "\n",
    "# CHANGE THE FOLLOWING \"PROJECT_DIR\" FILEPATH TO REFLECT LOCATION OF REPLICATION FOLDER\n",
    "PROJECT_DIR = '/Users/jjares/Documents/research/Farm Subsidies/replication_materials'\n",
    "GRAPHICS_OUTDIR = f'{PROJECT_DIR}/graphics'\n",
    "TABLES_OUTDIR = f'{PROJECT_DIR}/tables'\n",
    "survey_data_fpath = f'{PROJECT_DIR}/data/Survey Respondent Data for APSR Analyses.dta'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Read in Data and Convert Fields to Categorical for Plotting"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "respondents = pd.read_stata(survey_data_fpath)\n",
    "df = respondents.query('complete == 1').copy()\n",
    "\n",
    "# Convert 7-point ideology scale to Categorical\n",
    "ideology_bins = {\n",
    "    '0.00': 'Extremely Liberal', '0.17': 'Liberal', '0.33': 'Slightly Liberal', \n",
    "    '0.50': 'Moderate', \n",
    "    '0.67': 'Slightly Conservative', '0.83': 'Conservative', '1.00': 'Extremely Conservative'\n",
    "}\n",
    "df['ideology'] = pd.Categorical(\n",
    "    df['ideology'].apply(lambda x: '{0:0.2f}'.format(abs(x))).map(ideology_bins), \n",
    "    categories=list(ideology_bins.values()),\n",
    "    ordered=True\n",
    ")\n",
    "\n",
    "# Convert 6-point party ID to Categorical\n",
    "pid_bins = {\n",
    "    '0.00': 'Strong Democrat', '0.20': 'Not Strong Democrat', '0.40': 'Lean Democrat', \n",
    "    '0.60': 'Lean Republican', '0.80': 'Not Strong Republican', '1.00': 'Strong Republican'\n",
    "}\n",
    "df['pid6'] = pd.Categorical(\n",
    "    df['pid6'].apply(lambda x: '{0:0.2f}'.format(abs(x))).map(pid_bins), \n",
    "    categories=list(pid_bins.values()),\n",
    "    ordered=True\n",
    ")\n",
    "\n",
    "# Convert farmer identity to Categorical\n",
    "farmer_id_bins = {\n",
    "    '0.00': 'Not At All',\n",
    "    '0.25': 'A Little',\n",
    "    '0.50': 'A Moderate Amount',\n",
    "    '0.75': 'A Lot',\n",
    "    '1.00': 'A Great Deal'\n",
    "}\n",
    "df['identity_farmer'] = pd.Categorical(\n",
    "    df['identity_farmer'].apply(lambda x: '{0:0.2f}'.format(abs(x))).map(farmer_id_bins), \n",
    "    categories=list(farmer_id_bins.values()),\n",
    "    ordered=True\n",
    ")\n",
    "\n",
    "\n",
    "# Convert subsidy support to Categorical\n",
    "subsidy_bins = {\n",
    "    '0.0': 'Decreased', '0.5': 'Kept the Same', '1.0': 'Increased'\n",
    "}\n",
    "df['subsidies'] = pd.Categorical(\n",
    "    df['subsidies'].apply(lambda x: '{0:0.1f}'.format(abs(x))).map(subsidy_bins), \n",
    "    categories=list(subsidy_bins.values()),\n",
    "    ordered=True\n",
    ")\n",
    "\n",
    "# Convert MFP, CRP, ARC/PLC support to Categorical\n",
    "program_support_bins = {\n",
    "    '0.000': 'Strongly Oppose', '0.333': 'Somewhat Oppose', \n",
    "    '0.667': 'Somewhat Support', '1.000': 'Strongly Support'\n",
    "}\n",
    "for field in ['arc_support', 'crp_support', 'mfp_support']:\n",
    "    df[field] = pd.Categorical(\n",
    "        df[field].apply(lambda x: '{0:0.3f}'.format(abs(x))).map(program_support_bins), \n",
    "        categories=list(program_support_bins.values()),\n",
    "        ordered=True\n",
    "    )"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Online Appendix Figure 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Tabulate survey respondents by ideology\n",
    "ideology_counts = pd.DataFrame({\n",
    "  'freq': df['ideology'].value_counts(),\n",
    "  'prop': df['ideology'].value_counts(normalize=True)  \n",
    "})\n",
    "ideology_counts.index = ideology_counts.index.rename_categories(lambda x: x.replace(' ', '\\n').title())\n",
    "ideology_counts = ideology_counts.reset_index().rename(columns={'index': 'ideology_cat'})\n",
    "ideology_counts['order'] = ideology_counts['ideology_cat'].cat.codes\n",
    "ideology_counts = ideology_counts.sort_values('order').reset_index(drop=True)\n",
    "ideology_counts['percent'] = ideology_counts['prop'].apply(lambda f: '{:.1%}'.format(f))\n",
    "\n",
    "\n",
    "# Create bar plot\n",
    "fig, ax = plt.subplots(figsize=(9,6))\n",
    "plot = sns.barplot(\n",
    "    x=ideology_counts['ideology_cat'], \n",
    "    y=ideology_counts['freq'], \n",
    "    palette=np.linspace((0, 0, 1), (1, 0, 0), 7), \n",
    "    ax=ax\n",
    ")\n",
    "ax.set_ylabel('# of Respondents')\n",
    "ax.set_xlabel('')\n",
    "\n",
    "# Plot the percentages for each bar\n",
    "ax.set_ylim(top=ax.get_ylim()[1] + 10)\n",
    "for index, row in ideology_counts.iterrows():\n",
    "    plot.text(index, row['freq'] + 5, row['percent'], color='black', ha=\"center\")\n",
    "\n",
    "plt.savefig(f'{GRAPHICS_OUTDIR}/Online Appendix Figure 1.pdf', bbox_inches='tight')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Online Appendix Figure 2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Tabulate survey respondents by party ID\n",
    "partisan_counts = pd.DataFrame({\n",
    "  'freq': df['pid6'].value_counts(),\n",
    "  'prop': df['pid6'].value_counts(normalize=True)  \n",
    "})\n",
    "partisan_counts.index = partisan_counts.index.rename_categories(\n",
    "    lambda x: x.title().replace(' ', '\\n').replace('Not\\nStrong', 'Not Strong')\n",
    ")\n",
    "partisan_counts = partisan_counts.reset_index().rename(columns={'index': 'pid6'})\n",
    "partisan_counts['order'] = partisan_counts['pid6'].cat.codes\n",
    "partisan_counts = partisan_counts.sort_values('order').reset_index(drop=True)\n",
    "partisan_counts['percent'] = partisan_counts['prop'].apply(lambda f: '{:.1%}'.format(f))\n",
    "\n",
    "# Create bar plot\n",
    "fig, ax = plt.subplots(figsize=(9,6))\n",
    "plot = sns.barplot(\n",
    "    x=partisan_counts['pid6'], \n",
    "    y=partisan_counts['freq'], \n",
    "    palette=np.linspace((0, 0, 1), (1, 0, 0), 6), \n",
    "    ax=ax\n",
    ")\n",
    "ax.set_ylabel('# of Respondents')\n",
    "ax.set_xlabel('')\n",
    "\n",
    "# Plot the percentages for each bar\n",
    "ax.set_ylim(top=ax.get_ylim()[1] + 10)\n",
    "for index, row in partisan_counts.iterrows():\n",
    "    plot.text(index, row['freq'] + 5, row['percent'], color='black', ha=\"center\")\n",
    "plt.savefig(f'{GRAPHICS_OUTDIR}/Online Appendix Figure 2.pdf', bbox_inches='tight')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Online Appendix Figure 3"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_counts(varname, data=df):\n",
    "    counts = pd.DataFrame({\n",
    "      'freq': data[varname].value_counts(),\n",
    "      'prop': data[varname].value_counts(normalize=True)  \n",
    "    })\n",
    "    counts.index = counts.index.rename_categories(lambda x: x.title().replace(' ', '\\n') if len(x) > 13 \n",
    "                                                  else x.title().replace('The', 'the'))\n",
    "    counts = counts.reset_index().rename(columns={'index': varname})\n",
    "    counts['order'] = counts[varname].cat.codes\n",
    "    counts = counts.sort_values('order').reset_index(drop=True)\n",
    "    counts['percent'] = counts['prop'].apply(lambda f: '{:.1%}'.format(f))\n",
    "    return counts"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def plot_approval(varname, data=df, color=None, \n",
    "                  title=None, title_specs=(58, 0)):\n",
    "    counts = get_counts(varname)\n",
    "    ax = sns.barplot(x=counts[varname], y=counts['freq'], color=color)\n",
    "    ax.set_ylabel('# of Respondents')\n",
    "    ax.set_xlabel('')\n",
    "    if title is not None:\n",
    "        title_width, min_title_lines = title_specs[0], title_specs[1] - 1\n",
    "        wrapped_title = '\\n'.join(wrap(title, title_width))\n",
    "        blank_lines_to_add = min_title_lines - wrapped_title.count('\\n')\n",
    "        ax.set_title(wrapped_title + ('\\n' * blank_lines_to_add), multialignment='left')\n",
    "\n",
    "    # Plot the percentages for each bar\n",
    "    ax.set_ylim(top=660)\n",
    "    for index, row in counts.iterrows():\n",
    "        ax.text(index, row['freq'] + 5, row['percent'], color='black', ha=\"center\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Label colors\n",
    "seaborn_blue = (0.2980392156862745, 0.4470588235294118, 0.6901960784313725)\n",
    "seaborn_orange = (0.8666666666666667, 0.5176470588235295, 0.3215686274509804)\n",
    "seaborn_green = (0.3333333333333333, 0.6588235294117647, 0.40784313725490196)\n",
    "seaborn_red = (0.7686274509803922, 0.3058823529411765, 0.3215686274509804)\n",
    "\n",
    "programs = ['subsidies', 'mfp_support', 'arc_support', 'crp_support']\n",
    "program_color_specs = dict(zip(programs, [seaborn_blue, seaborn_orange, seaborn_red, seaborn_green]))\n",
    "program_titles = {\n",
    "    'subsidies': ('Do you think agricultural subsidies paid '\n",
    "                  'to farmers should be increased, decreased, or kept the same?'),\n",
    "    'mfp_support': ('Do you support or oppose the USDA’s Market Facilitation Program (MFP), '\n",
    "                    'which provides assistance to farmers with commodities impacted by '\n",
    "                    'foreign tariffs?'),\n",
    "    'arc_support': ('Do you support or oppose the USDA’s Agricultural Risk Coverage (ARC) '\n",
    "                    'and Price Loss Coverage (PLC) programs, which provide income support '\n",
    "                    'payments when crop revenues and prices drop below certain levels?'),\n",
    "    'crp_support': ('Do you support or oppose the USDA’s Conservation Reserve Program (CRP), '\n",
    "                    'which provides financial and technical assistance to farmers to protect '\n",
    "                    'natural resources?')\n",
    "}\n",
    "program_title_specs = {\n",
    "    'subsidies': (58, 3),\n",
    "    'mfp_support': (58, 3),\n",
    "    'arc_support': (58, 4),\n",
    "    'crp_support': (58, 4)\n",
    "}\n",
    "\n",
    "for position, outcome in enumerate(programs):\n",
    "    g = plt.subplot(2, 2, position + 1)\n",
    "    plot_approval(outcome, data=df, color=program_color_specs[outcome], \n",
    "                  title=program_titles[outcome], title_specs=program_title_specs[outcome])\n",
    "    \n",
    "f = g.get_figure()\n",
    "f.set_size_inches(12, 12)\n",
    "plt.subplots_adjust(hspace = 0.4)\n",
    "plt.savefig(f'{GRAPHICS_OUTDIR}/Online Appendix Figure 3.pdf', bbox_inches='tight')\n",
    "\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Further Supplemental Information Figure 4"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Rescale outcomes to read better on the Y-axis\n",
    "df['thousands_acres'] = df['total_acres'] * 10\n",
    "df['millions_farm_value'] = df['farm_value_2019'] * 10\n",
    "\n",
    "left = plt.subplot(1, 2, 1)\n",
    "ax = sns.boxplot(x='identity_farmer', y='total_acres', data=df, showfliers=False)\n",
    "ax.set(xlabel='', ylabel='Total Acres Operated (Thousands)')\n",
    "\n",
    "right = plt.subplot(1, 2, 2)\n",
    "ax = sns.boxplot(x='identity_farmer', y='farm_value_2019', data=df, showfliers=False)\n",
    "ax.set(xlabel='', ylabel='Value of Land Operated (Millions of 2019 Dollars)')\n",
    "\n",
    "f = right.get_figure()\n",
    "f.set_size_inches(16, 8)\n",
    "plt.subplots_adjust(wspace = 0.21)\n",
    "question_text = ('People often describe themselves in various ways, for example by their nationality,\\n'\n",
    "                 'their religion, or their occupation. How much do you think of yourself as a “farmer”?')\n",
    "plt.rcParams.update({'font.size': 13})\n",
    "plt.suptitle(question_text, x=0.5, y=0.05, fontsize=18)\n",
    "plt.savefig(f'{GRAPHICS_OUTDIR}/Further Supplemental Information Figure 4.pdf', bbox_inches='tight')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Further Supplemental Information Table 5"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def one_way_anova_pvalue(var, df1, df2, df3):\n",
    "    results = stats.f_oneway(\n",
    "        df1.loc[df1[var].notnull()][var], \n",
    "        df2.loc[df2[var].notnull()][var], \n",
    "        df3.loc[df3[var].notnull()][var]\n",
    "    )\n",
    "    return results.pvalue"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Define fields indicating attrition\n",
    "respondents['Completed Survey'] = respondents['complete']\n",
    "respondents['Answered MFP Support'] = respondents['mfp_support'].notnull()\n",
    "respondents['Answered ARC/PLC Support'] = respondents['arc_support'].notnull()\n",
    "respondents['Answered CRP Support'] = respondents['crp_support'].notnull()\n",
    "respondents['Answered Trump Approval'] = respondents['trump_approve'].notnull()\n",
    "respondents['Government Positivity Index'] = respondents['gov_avg'].notnull()\n",
    "attrition_fields = [\n",
    "    'Completed Survey', 'Answered MFP Support', 'Answered ARC/PLC Support',\n",
    "    'Answered CRP Support', 'Answered Trump Approval', 'Government Positivity Index'\n",
    "]\n",
    "\n",
    "# Calculate frequency at which respondents answered\n",
    "attrition = pd.DataFrame({\n",
    "    'ARC/PLC Group': (respondents.query('(condition == \"arc\")')\n",
    "                                 .loc[:, attrition_fields]\n",
    "                                 .mean()\n",
    "                                 .apply(lambda x: '{0:.1%}'.format(x))),\n",
    "    'Control Group': (respondents.query('(condition == \"control\")')\n",
    "                                 .loc[:, attrition_fields]\n",
    "                                 .mean()\n",
    "                                 .apply(lambda x: '{0:.1%}'.format(x))),\n",
    "    'CRP Group': (respondents.query('(condition == \"crp\")')\n",
    "                             .loc[:, attrition_fields]\n",
    "                             .mean()\n",
    "                             .apply(lambda x: '{0:.1%}'.format(x))),\n",
    "})\n",
    "\n",
    "# Add in a one-way ANOVA test p-value\n",
    "attrition['One-Way ANOVA'] = (\n",
    "    pd.Series(attrition_fields, index=attrition_fields)\n",
    "      .apply(lambda field: one_way_anova_pvalue(field, respondents.query('controltreat == 1'),\n",
    "                                                       respondents.query('arctreat == 1'),\n",
    "                                                       respondents.query('crptreat == 1')))\n",
    ")\n",
    "\n",
    "# Write a latex table to file\n",
    "latex = attrition.to_latex()\n",
    "with open(f'{TABLES_OUTDIR}/Further Supplemental Information Table 5.tex', 'w+') as f:\n",
    "    f.write(latex)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "attrition"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
